package top.hekun.study.core.visitor.method.complex;

import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;

/**
 * 〈输出打印语句的代码〉    System.out.println("执行 HelloWordComplex#add3 方法");
 *
 * @author: Sakura
 * @date: 2023/5/13
 */
public class MyMethodVisitor3 extends PatternMethodVisitor {
    private String thisClassName = this.getClass().getSimpleName();


    protected final static int SEEN_GETSTATIC = 1;
    protected final static int SEEN_GETSTATIC_LDC = 2;

    Object ldcValue;

    protected MyMethodVisitor3(int api, MethodVisitor methodVisitor) {
        super(api, methodVisitor);
    }


    //     methodVisitor.visitMethodInsn(INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/String;)V",false);
    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
        switch (state) {
            case SEEN_GETSTATIC_LDC:
                if (opcode == INVOKEVIRTUAL &&
                        "java/io/PrintStream".equals(owner) &&
                        "println".equals(name) &&
                        "(Ljava/lang/String;)V".equals(descriptor)
                ) {
                    state = SEEN_NOTHING;
                    return;
                }
                break;
        }
        super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
    }


    @Override
    public void visitLdcInsn(Object value) {
        switch (state) {
            case SEEN_GETSTATIC:
                if (value instanceof String) {

                    state = SEEN_GETSTATIC_LDC;
                    ldcValue = value;
                    return;
                }
                break;
        }
        super.visitLdcInsn(value);
    }

    //     methodVisitor.visitFieldInsn(GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");
    @Override
    public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
        boolean b = opcode == GETSTATIC &&
                "java/lang/System".equals(owner) &&
                "out".equals(name) &&
                "Ljava/io/PrintStream;".equals(descriptor);
        switch (state) {
            case SEEN_NOTHING:
                if (b) {
                    state = SEEN_GETSTATIC;
                    return;
                }
            case SEEN_GETSTATIC:
                if (b) {
                    state = SEEN_GETSTATIC;
                    mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                    return;
                }
                break;
        }
        super.visitFieldInsn(opcode, owner, name, descriptor);
    }

    /**
     * 兼职状态的初始化 状态的回归
     */
    @Override
    public void visitInsn() {
//        System.out.println("state: " + state);
        switch (state) {
            case SEEN_GETSTATIC:
                mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                break;
            case SEEN_GETSTATIC_LDC:
                mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                mv.visitLdcInsn(ldcValue);
                break;

        }
        //  首次进入的时候  赋值 state= SEEN_NOTHING
        state = SEEN_NOTHING;
    }
}
